/*
- @Author: Wangjun
- @Date: 2021-05-21 14:44:32
  - @LastEditTime: 2025-05-01 15:23:48
  - @LastEditors: wangjun haodreams@163.com

- @Description:
- @FilePath: copy form libs/buffer.go
- hnxr
*/
package serial

import (
	"errors"
	"fmt"
	"io"
)

var ErrFull = errors.New("缓冲区空间不够")
var ErrNotEnoughData = errors.New("缓冲区没有足够的数据")

// 高性能的循环缓存,数据0分配
type LoopBuffer struct {
	buf        []byte //缓冲区
	cap        int    //最大容量
	readPos    int    //读开始位置
	writePos   int    //写开始位置
	disableEof bool   //没有可用的数据不返回EOF标志，默认返回io.EOF
}

func NewLoopBuffer(data []byte) *LoopBuffer {
	m := new(LoopBuffer)
	m.SetData(data)
	return m
}

func (m *LoopBuffer) Cap() int {
	return int(m.cap)
}

// 缓冲区可读取字符长度( 可读的大小)
func (m *LoopBuffer) Len() int {
	size := m.writePos - m.readPos
	if size < 0 {
		return m.writePos + m.cap - m.readPos // -size
	}
	return size
}

// 可写的大小
func (m *LoopBuffer) AvailWrite() int {
	return m.cap - m.Len()
}

// 设置整个缓存都可以读取
func (m *LoopBuffer) SetCanReadAll() *LoopBuffer {
	m.readPos = 0
	m.writePos = m.cap
	return m
}

func (m *LoopBuffer) SetDisableEOF() *LoopBuffer {
	m.disableEof = true
	return m
}

// 实现Read 接口
func (m *LoopBuffer) Read(p []byte) (n int, err error) {
	if m.Len() == 0 {
		if m.disableEof { //不返回EOF标志， 一般用在串口通信中
			return
		}
		return 0, io.EOF
	}
	if m.readPos < m.writePos {
		n = copy(p, m.buf[m.readPos:m.writePos])
		m.readPos += n
		return
	}
	n = copy(p, m.buf[m.readPos:]) //读取前面一部分
	if n == len(p) {               //读满了
		m.readPos += n
		return
	}
	m.readPos += n
	l := m.Len()
	m.readPos = copy(p[n:], m.buf[:l]) //读取后面一部分
	n += m.readPos
	return
}

// 实现Write 接口
// 使用前必须保证有足够的剩余空间
func (m *LoopBuffer) Write(p []byte) (n int, err error) {
	n = len(p)
	if n > m.AvailWrite() {
		return 0, ErrFull
	}
	//尾部没有足够的空间写入数据
	if (m.cap - m.writePos) < n {
		//先写尾部，再写前部
		n = copy(m.buf[m.writePos:], p)
		m.writePos = copy(m.buf, p[n:])
		n += m.writePos
		return
	}
	n = copy(m.buf[m.writePos:], p)
	m.writePos += n
	return
}
func (m *LoopBuffer) PutByte(b byte) {
	m.buf[m.writePos] = b
	m.writePos++
	m.writePos = m.writePos % m.cap
}

// 写入字符串
func (m *LoopBuffer) WriteString(text string) (n int, err error) {
	return m.Write([]byte(text))
}
func (m *LoopBuffer) Printf(format string, a ...any) (n int, err error) {
	return fmt.Fprintf(m, format, a...)
}

// TODO 增加 WriteString WriteByte 并整理 reader writer 功能
func (m *LoopBuffer) Reset() {
	m.readPos = 0
	m.writePos = 0
}

func (m *LoopBuffer) Bytes() []byte {
	if m.Len() == 0 {
		return nil
	}
	if m.readPos < m.writePos {
		return m.buf[m.readPos:m.writePos]
	}
	data := make([]byte, m.Len())
	size := copy(data, m.buf[m.readPos:]) //读取前面一部分
	m.readPos = copy(data[size:], m.buf)  //读取后面一部分
	return data
}

func (m *LoopBuffer) String() string {
	return string(m.Bytes())
}

// 设置数据缓冲区并对数据进行复位操作
func (m *LoopBuffer) SetData(data []byte) *LoopBuffer {
	m.buf = data
	m.cap = len(m.buf)
	m.Reset()
	return m
}
